09. Guardrails 与 Observability
本章参考 OpenAI agent safety 文档、LangChain / LangGraph 关于 LangSmith 的最新文档、OpenTelemetry GenAI Semantic Conventions、以及 Langfuse / Phoenix 等开源 LLM observability 方案。
本章高频面试题
- 什么是 Guardrails?它和普通的安全提示词有什么区别?
- 为什么说 Guardrails 不能只靠 Prompt,而必须是系统级能力?
- 输入 Guardrails、上下文 Guardrails、输出 Guardrails、工具 Guardrails、执行路径 Guardrails 分别是什么?
- 什么是 Observability?它和日志记录有什么区别?
- 为什么 Agent 比普通后端服务更需要 Observability?
- OpenTelemetry GenAI Semantic Conventions 当前是什么状态?应该怎么用?
- LangSmith、Langfuse、Phoenix、Helicone 应该怎么选?
- 一个生产级 Agent 系统最少应该监控哪些指标?
- 如何用 trace、run、thread 这些概念去理解 Agent 观测体系?
- Guardrails 和 Human-in-the-loop 有什么关系?什么时候该拦截,什么时候该审批?
- LLM-as-judge 怎么做才可靠?怎么避免裁判偏见?
- Evals 类型(offline、online、human、deterministic)怎么组合?
- Prompt/model 升级的灰度与回滚怎么做?
1. 什么是 Guardrails
Guardrails 可以理解成:
围绕 Agent 输入、上下文、输出、工具调用和执行路径设置的一组约束、检查和拦截机制,用来降低错误、滥用和风险。
它不是一个单一组件,而是一整套策略。常见 Guardrails:
- 输入检查
- 上下文检查
- 输出检查
- 工具调用前校验
- 权限和审批门禁
- 结构化输出校验
- 风险内容拦截
一句话:
Guardrails 就是让 Agent”不能想怎么做就怎么做”的一套安全和质量边界。
2. Guardrails 和 Prompt 的区别
在 system prompt 里写规则只是”最弱的一层”。
Prompt 的作用是:告诉模型应该怎么做、提醒模型遵守规则。
但真正的 Guardrails 必须还包括:
- 程序化检查
- 拦截
- 审批
- 校验
- 降级或失败处理
因为 Prompt 无法保证:
- 模型一定听话
- 外部内容不会污染模型
- 高风险工具不会被误调用
结论:
Prompt 可以表达 Guardrails 意图,但 Guardrails 不能只靠 Prompt 实现。
3. Guardrails 的几个层次
3.1 输入 Guardrails
在模型处理用户输入前先做检查:
- PII 检测和脱敏(Presidio、LlamaGuard)
- Jailbreak / injection 检测(Prompt Guard、Rebuff)
- 非法内容、仇恨言论、未成年相关内容
- Input token budget 限制
OpenAI、Anthropic 官方安全文档都明确推荐这一层。
3.2 上下文 Guardrails(容易被忽略)
不只是用户输入,外部检索结果、网页内容、工具返回文本也可能带来注入风险。
- 不要把不可信文本直接当成指令
- 把外部内容和系统规则明确分层(XML tags、section headers)
- 优先抽取结构化字段,而不是把整段任意文本直接串进关键决策链路
- 已知的 injection 模式用 regex/分类器预过滤
3.3 输出 Guardrails
模型产出后再检查:
- JSON Schema 校验(Zod、io-ts)
- 敏感信息扫描(PII、API key、内部 URL)
- 格式合规(引用格式、链接白名单)
- 违规内容二次分类(LlamaGuard output version)
- 字数/token 上限(避免失控生成)
3.4 工具 Guardrails
工具调用前后做检查:
- 参数 schema 校验
- 参数值域 allowlist(邮件域名、金额上限)
- 权限校验(principal 有没有权限调这个工具)
- 风险等级判断和审批触发
- 工具返回结果是否合法
3.5 执行路径 Guardrails
Agent 的执行流程本身也需要 Guardrails:
- 最大步数限制
- 最大重试次数
- 最大同类工具调用次数(避免循环)
- 禁止某些危险组合路径(搜索 → 直接发邮件 链路需要人工介入)
- Budget circuit breaker(见第 5 章)
4. Guardrails 的工程方法论
4.1 先识别风险,再决定 Guardrails
不要为了”看起来专业”就堆很多 Guardrails。先问清楚:
- 系统会处理什么数据
- 会执行什么动作
- 哪些错误代价最高
- 哪些内容来自不可信源
然后按风险分层去设计 Guardrails。
4.2 优先做程序化 Guardrails
稳定的顺序:
- 权限和工具可见性控制
- 输入/输出 schema 校验
- 高风险动作审批(HITL)
- 内容检测和分类(LLM classifier)
- Prompt 级提醒(最弱一层)
真正可靠的 Guardrails 通常更像系统设计,而不是提示词写作。
4.3 对外部内容默认不完全信任
OpenAI 官方安全文档强调的原则:
不要让不可信文本直接驱动高风险行为。
常见来源:检索到的网页、外部邮件、第三方 API 返回、MCP server 的 tool description。治理见第 8 章。
5. Guardrail 工具选型
- Llama Guard (Meta):开源、双向(输入+输出)分类器,轻量,自托管友好
- Prompt Guard (Meta):专用 injection/jailbreak 分类
- NeMo Guardrails (NVIDIA):规则 + LLM 双层,支持 Colang DSL,功能最全
- Rebuff (ProtectAI):专注 prompt injection,多层防御
- Presidio (Microsoft):PII 检测与脱敏,成熟稳定
- OpenAI Moderation API:托管的内容审核,免费,覆盖 OpenAI policies
选型原则:
- 自托管优先 Llama Guard + Presidio
- 需要规则可配置(合规场景)用 NeMo Guardrails
- OpenAI 生态内默认开启 Moderation
6. 什么是 Observability
Observability 不是简单写日志,而是:
让你能够通过系统输出的数据,理解 Agent 当时做了什么、为什么这么做、在哪一步出错、问题属于哪一类。
在 Agent 系统里,这意味着你需要能看到:
- 模型调用(prompt、response、usage、latency、cost)
- 工具调用(name、args、result、error)
- 检索结果(query、hits、scores)
- 规划步骤(plan snapshot、decision log)
- 中断和恢复(interrupt payload、resume decision)
- 最终输出
7. 为什么 Agent 比普通后端更需要 Observability
Agent 系统更复杂:模型不确定性、多步执行、外部工具、上下文动态变化、中间状态。
普通接口出错只需要看 request / response / stack trace。 Agent 出错需要知道:
- 当时看到了哪些 context
- 选了哪个工具
- 为什么选它
- 检索到了什么
- 中间有没有重试
- 哪一步开始跑偏
- 对应的 prompt 版本和模型版本
这就是为什么 LangChain / LangGraph 文档把 Observability 放得很重要,并通过 LangSmith 强调 traces / runs / threads 这套模型。
8. 核心概念:Trace、Run、Thread
按 LangSmith 官方文档的定义:
8.1 Trace
一次完整操作的执行轨迹——“用户发起一个任务,到最终结果返回”的整条链路。
8.2 Run
Trace 里的一个执行步骤:一次 LLM 调用、一次 tool call、一次检索、一个子链路。
8.3 Thread
把多次相关 trace 串起来的一条长会话或长任务上下文。
这个模型天然支持:
- 单次任务排障
- 多轮会话分析
- 跨步骤性能诊断
9. OpenTelemetry GenAI Semantic Conventions
这是 Agent observability 的工业级事实标准,虽然当前(2026-04)仍处于 development 状态。
9.1 当前状态
OTel 社区 2024 年启动 GenAI SIG,定义了 LLM / Agent / tool call 的统一 span 属性和 metric 命名。当前状态:
- Development(非 stable),但已被多家 vendor 采用
- 通过环境变量
OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental启用最新版 - 已有针对 Anthropic / OpenAI / Azure AI Inference / AWS Bedrock / MCP 的技术特定约定
9.2 关键 Span 类型
- LLM call span:
gen_ai.operation.name = "chat" | "generate_content" | ... - Agent span:表示一次 agent run
- Tool call span:表示工具调用
- Embedding span / Rerank span
9.3 关键属性(示意)
gen_ai.system:openai/anthropic/bedrock/mcpgen_ai.request.model:请求的模型 IDgen_ai.response.model:实际响应的模型(可能不同于请求,例如 fallback)gen_ai.usage.input_tokens/gen_ai.usage.output_tokens/gen_ai.usage.total_tokensgen_ai.request.temperature/gen_ai.request.top_p/gen_ai.request.max_tokensgen_ai.response.finish_reasons- Tool 调用相关:
gen_ai.tool.name/gen_ai.tool.call.id
9.4 为什么值得走 OTel 规范
- 跨 vendor 一致性:换 observability provider 不用重新 instrument
- 和非 LLM 的可观测性打通:Agent tool call 可以和下游数据库/API 的 trace 串起来
- 未来稳定性投资:stable 版本发布后,基础字段不会大改
实操上:业务代码用 OTel SDK + GenAI conventions 打点,后端可以同时发到 LangSmith / Langfuse / Phoenix / Jaeger。
10. LLM Observability 平台选型
| 平台 | 类型 | 适合场景 |
|---|---|---|
| LangSmith | 托管 | LangChain 生态深度集成、trace 体验好 |
| Langfuse | 开源 + 托管 | 自托管友好、provider 无关、成本归因强 |
| Phoenix (Arize) | 开源 + 托管 | OTel 原生、evals 框架强 |
| Helicone | 托管 | 代理型接入(改 baseURL 即可)、成本控制 |
| Honeycomb / Datadog | 通用 APM | 已有通用 observability 栈的扩展 |
| 自研 | 基于 OTel Collector + Grafana | 极致定制、合规场景 |
选型原则:
- 深度 LangChain 用户 → LangSmith
- 多 provider、自托管、成本归因 → Langfuse
- 重度 evals + OTel 原生 → Phoenix
- 快速接入、最低侵入 → Helicone
- 已有 Datadog/Honeycomb → 走 OTel 打通
11. 生产级 Agent 最少应该观测什么
11.1 运行指标
- Run 成功率 / 失败率
- 平均时延、p95、p99(尾延迟才是真相)
- 首包时延 (TTFB)
- 平均 token 消耗(prompt + completion)
- 平均成本($USD)
- Trajectory 长度(步数分布)
11.2 模型指标
- 模型调用次数
- Prompt cache 命中率(非常关键,见第 3 章)
- 结构化输出失败率
- 模型错误率 / fallback 触发率
- Per-provider 可用性(多 provider 路由必须观测)
11.3 工具指标
- 工具选择准确率 + specificity(不该调用时没调)
- 参数填充正确率
- 工具成功率
- 参数校验失败率
- 平均工具耗时
- 高风险工具审批通过率
- Idempotency key 重复命中率(反映重试/去重健康度)
11.4 检索指标
- Top-k 命中率
- 召回延迟
- Rerank 后命中率
- 空召回率
- Contextual retrieval 的 context generation 失败率
11.5 人工介入指标
- HITL 触发率
- 审批拒绝率
- 审批后修改率
- 审批平均耗时(影响用户体验)
- 超时审批率
11.6 成本归因
- Per-workspace / per-user / per-feature / per-tool 的 token + $ 归因
- 单任务平均成本的时间趋势
- Prompt cache 带来的节省
12. Observability 不只是 tracing
完整的 Observability 至少包括:
- Tracing:看执行链路和每一步细节
- Metrics:看成功率、耗时、成本、错误率等宏观指标
- Logs:看原始事件、错误信息和上下文记录
- Feedback / Annotation:看人工反馈和质量标注(thumbs up/down、纠正、标签)
- Evaluations:看系统在标准任务集上的表现
如果只有日志,没有 trace、指标和评估,严格来说还不算完整可观测。
13. Evals:让”好”变得可度量
Evals 是把 Agent 从”看着差不多”做到”真的能上线”的关键。
13.1 Evals 分类
- Deterministic evals:字符串匹配、regex、JSON schema 校验、数值精确比对。适合确定性输出
- LLM-as-judge:用另一个(通常更强的)LLM 按 rubric 打分。适合开放式任务
- Human evals:人工标注,代价最高但最准
- Online evals:从生产流量采样 + feedback 自动评估
- A/B evals:同一请求跑两个 prompt/model 版本,结果对比
13.2 LLM-as-judge 的最佳实践
LLM-as-judge 是最容易做错的一环,几条工程规矩:
- 结构化 rubric:不要让 judge 打个 1-10,让它按多个维度分别判定(事实准确、格式合规、未幻觉、引用正确),返回 JSON
- 避免 position bias:pairwise 比较时随机化顺序,或同时跑两个顺序取平均
- 避免 self-preference:判官不要和被评估的模型是同一个(或至少做交叉)
- Few-shot:给 judge 2-3 个带标注的例子,校准它的判断
- 一致性检测:同一个样本跑多次,判官结果应该一致;不一致的样本标记为 low confidence
- 和人工 gold 校准:judge 的判断要定期和人工标注对齐,漂移了就更新 prompt
13.3 Eval 数据集的层次
- Gold set:人工精标的标准集,规模 50-200 条覆盖核心场景
- Adversarial set:故意构造的 badcase(容易误触发、边界条件、对抗输入)
- 回归集:历史 bugfix 和 feature 验证样本,每次迭代必过
- 真实流量采样:生产里随机采样 + 脱敏,反映真实分布
13.4 Eval 放在 CI
- Prompt / model / skill / tool 任何变更必须跑回归集
- 指标有阈值,下降超阈值阻塞合并
- Eval 结果有历史趋势,看长期变化
- 成本 / 延迟 / trajectory 长度也是 eval 指标,不只有”对不对”
14. Prompt / Model 升级的灰度和回滚
模型供应商升级(Opus 4.6 → 4.7)或自己改 prompt,不能直接全量切换。
14.1 灰度模式
- Shadow mode:新旧 prompt/model 同时跑,只用旧版本的结果返回给用户,新版本结果只记录用于对比
- Canary:新版本放 1% → 5% → 20% → 100%,每阶段看指标
- User segmentation:按 workspace、role、geography 分组灰度
- Feature flag:运行时开关,一键回滚
14.2 必须监控的回归指标
- 任务成功率
- P95 延迟
- Trajectory 长度
- 成本
- Tool call 准确率
- Prompt cache 命中率(换模型可能破坏缓存)
- 用户 thumbs-down 率
任何一项退步超阈值 → 自动回滚,不等人决定。
15. TypeScript 示例:给一次 run 打 trace metadata + OTel 约定
import { trace, SpanKind } from "@opentelemetry/api";
const tracer = trace.getTracer("agent-runtime");
type AgentRunInput = {
runId: string;
threadId: string;
userId: string;
workspaceId: string;
promptVersion: string;
model: string;
taskType: string;
};
export async function runAgent<T>(
input: AgentRunInput,
fn: () => Promise<T>
): Promise<T> {
return tracer.startActiveSpan(
"agent.run",
{
kind: SpanKind.INTERNAL,
attributes: {
// OTel GenAI conventions
"gen_ai.system": "anthropic",
"gen_ai.request.model": input.model,
"gen_ai.operation.name": "agent",
// 业务维度
"agent.run_id": input.runId,
"agent.thread_id": input.threadId,
"agent.task_type": input.taskType,
"agent.prompt_version": input.promptVersion,
"user.id": input.userId,
"workspace.id": input.workspaceId,
},
},
async (span) => {
try {
const result = await fn();
span.setStatus({ code: 1 }); // OK
return result;
} catch (err) {
span.recordException(err as Error);
span.setStatus({ code: 2, message: (err as Error).message });
throw err;
} finally {
span.end();
}
}
);
}这个例子体现几点:
- 用 OTel GenAI conventions 做跨 vendor 一致的打点
- 业务维度(
workspace.id等)作为附加属性,便于归因和过滤 - 异常自动记录到 span
- Cost/latency 可以由 OTel Collector 聚合成 metrics
16. Guardrails 和 Observability 的闭环
成熟系统里,这两者不是分离的:
- Guardrails 在运行时做拦截和校验
- Observability 记录 Guardrails 触发点(为什么被拦、哪类输入触发)
- 失败样本 进入 eval 集和人工分析
- 反过来优化 prompt、工具边界和 Guardrails 规则
例如:
- 某类工具误调用频繁 → trace 发现都来自同一类用户输入 → 补一个输入 Guardrail 或更严格的 tool visibility 规则
- Prompt injection 在某些 indirect source 上高频 → 增加该 source 的 sanitization + dual-LLM
- HITL 拒绝率在某类动作上异常高 → 调整默认参数或引入额外校验
这才叫系统性优化。
17. Guardrails 和 Human-in-the-loop 的关系
- Guardrails 更像自动边界和自动检查
- HITL 更像关键节点的人类决策
两者协同:
- 先用 Guardrails 自动过滤明显风险(拦截 injection、schema 错误、越权)
- 对高风险但无法完全自动判断的动作,进入 HITL
Guardrails 负责自动防护,HITL 负责高风险兜底。
18. 什么时候说明你的系统”Guardrails 不够”
- 模型经常看到不该看到的工具
- 高风险工具误触发后才靠人工补救
- 输出经常不符合 schema
- 外部检索内容经常把模型带偏
- 线上出错后看不到当时 context 和调用链
- Prompt cache 命中率常年 < 50%
- 没有 trace 或无法按
run_id快速定位
这些信号说明问题不只是”模型偶发不稳定”,而是系统边界不清晰。
19. 本章方法论小结
- Guardrails 不是一句提示词,而是一整套系统边界(输入/上下文/输出/工具/执行路径)
- Prompt 只能表达规则,不能替代强制校验
- 对外部不可信内容默认要做隔离和结构化处理
- Observability 不只是日志,还包括 traces、metrics、feedback 和 evals
- OpenTelemetry GenAI Semantic Conventions 是跨 vendor 的事实标准(当前 experimental),值得作为打点基线
- LangSmith / Langfuse / Phoenix / Helicone 按场景选型,都可以和 OTel 协作
- Agent 观测体系应覆盖模型、工具、检索、审批、成本、trajectory 长度、prompt cache 命中率
- Evals 分 deterministic / LLM-judge / human / online,组合使用
- LLM-as-judge 必须结构化 rubric + 避免 position/self bias + 人工校准
- Prompt/model 升级走 shadow → canary → 全量,配套自动回滚
- Guardrails 和 Observability 应该组成”防护 + 诊断 + 迭代”的闭环